package com.xsq.rpc.center.server.listener;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.xsq.rpc.center.server.config.DruidDataSourceHandler;
import com.xsq.rpc.common.config.CuratorZookeeperProperties;
import com.xsq.rpc.common.config.ServerConfig;
import com.xsq.rpc.common.config.ZookeeperConfigurationCentreProperties;
import com.xsq.rpc.common.model.RpcMapper;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import lombok.extern.slf4j.Slf4j;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.cache.ChildData;
import org.apache.curator.framework.recipes.cache.TreeCache;
import org.apache.curator.framework.recipes.cache.TreeCacheEvent;
import org.apache.curator.framework.recipes.cache.TreeCacheListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;

/**
 * @ClassName PathChildrenListener
 * @Description TODO
 * @Author xsq
 * @Date 2020/6/10 15:06
 **/
@Slf4j
public class PathChildrenListener {

    public final static Map<String, RpcMapper> RPCMAPPERS = new ConcurrentHashMap<>();

    private CuratorFramework client;

    private CuratorZookeeperProperties curatorZookeeperProperties;

    private ZookeeperConfigurationCentreProperties dataSourceConfigProperties;

    private ServerConfig serverConfig;


    private DruidDataSourceHandler druidDataSourceHandler;


    private static CountDownLatch watch = new CountDownLatch(1);


    public PathChildrenListener(CuratorFramework client, CuratorZookeeperProperties curatorZookeeperProperties, ServerConfig serverConfig, ZookeeperConfigurationCentreProperties dataSourceConfigProperties, DruidDataSourceHandler druidDataSourceHandler) {
        this.client = client;
        this.curatorZookeeperProperties = curatorZookeeperProperties;
        this.serverConfig = serverConfig;
        this.dataSourceConfigProperties = dataSourceConfigProperties;
        this.druidDataSourceHandler = druidDataSourceHandler;
    }

    /**
     * 注册监听
     * TreeCache: 可以将指定的路径节点作为根节点（祖先节点），对其所有的子节点操作进行监听，
     * 呈现树形目录的监听，可以设置监听深度，最大监听深度为 int 类型的最大值。
     */
    public void zkWatch(String path) throws Exception {
        TreeCache treeCache = new TreeCache(client, path);

        treeCache.getListenable().addListener(new TreeCacheListener() {
            @Override
            public void childEvent(CuratorFramework client, TreeCacheEvent event) throws Exception {
                ChildData eventData = event.getData();
                switch (event.getType()) {
                    case NODE_ADDED:
                        log.warn("节点添加" + eventData.getPath() + "\t添加数据为：" + new String(eventData.getData()));
                        updateDataSource(new String(eventData.getData()));
                        break;
                    case NODE_UPDATED:
                        log.warn(eventData.getPath() + "节点数据更新\t更新数据为：" + new String(eventData.getData()) + "\t版本为：" + eventData.getStat().getVersion());
                        updateDataSource(new String(eventData.getData()));
                        break;
                    case NODE_REMOVED:
                        log.warn(eventData.getPath() + "节点被删除");
                        break;
                    default:
                        break;
                }
            }
        });

        treeCache.start();
        watch.await();  //如果不执行 watch.countDown()，进程会一致阻塞在 watch.await()
    }


    private void updateDataSource(String data) {
        if (!StringUtils.isEmpty(data)) {
            JSONObject userJson = JSONObject.parseObject(data);
            ZookeeperConfigurationCentreProperties datasource = JSON.toJavaObject(userJson, ZookeeperConfigurationCentreProperties.class);
            try {
                druidDataSourceHandler.updateDataSource(datasource);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 获取节点内容
     *
     * @param client
     * @param path
     * @return
     */
    public String getZnodeValue(CuratorFramework client, String path) {
        //获取节点内容
        try {
            return new String(client.getData().forPath(path));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    // 关闭连接
    private void closeZnode() {
        if (client != null) {
            client.close();
        }
    }


    /**
     * 转化数据
     *
     * @param zookeeperConfigurationCentreProperties
     * @param hikariDataSourceOld
     */
    private HikariDataSource conversionData(ZookeeperConfigurationCentreProperties zookeeperConfigurationCentreProperties, HikariDataSource hikariDataSourceOld) {
        hikariDataSourceOld.isClosed();
        //初始化连接pool
        HikariConfig hikariConfig = new HikariConfig();
        hikariConfig.setDriverClassName(zookeeperConfigurationCentreProperties.getDriverClassName());
        hikariConfig.setJdbcUrl(zookeeperConfigurationCentreProperties.getJdbcUrl());
        hikariConfig.setUsername(zookeeperConfigurationCentreProperties.getUsername());
        hikariConfig.setPassword(zookeeperConfigurationCentreProperties.getPassword());
        HikariDataSource dataSource = new HikariDataSource(hikariConfig);
        hikariDataSourceOld = dataSource;
        return hikariDataSourceOld;
    }

}
